import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_common/flutter_common.dart';

class SwipeLayout extends StatefulWidget {
  const SwipeLayout({Key? key,
        required this.child,
        required this.buttons,
        required this.onClick,
        this.singleButtonWidth = 60,
        this.autoClose = true,
        this.onSlideStarted,
        this.onSlideCompleted,
        this.onSlideCanceled,
        })
      : super(key: key);

  final Widget child;

  final List<Widget> buttons;

  final double? singleButtonWidth;

  final VoidCallback? onSlideStarted;

  final VoidCallback? onSlideCompleted;

  final VoidCallback? onSlideCanceled;

  final Function(SwipeLayoutState, int) onClick;

  final bool? autoClose;

  @override
  SwipeLayoutState createState() => SwipeLayoutState();
}

class SwipeLayoutState extends State<SwipeLayout>
    with TickerProviderStateMixin, FxState {
  double translateX = 0;
  late double maxDragDistance;
  final Map<Type, GestureRecognizerFactory> gestures =
  <Type, GestureRecognizerFactory>{};

  late AnimationController animationController;

  @override
  void initState() {
    super.initState();

    maxDragDistance = widget.singleButtonWidth! * widget.buttons.length;
    gestures[HorizontalDragGestureRecognizer] =
        GestureRecognizerFactoryWithHandlers<HorizontalDragGestureRecognizer>(
              () => HorizontalDragGestureRecognizer(debugOwner: this),
              (HorizontalDragGestureRecognizer instance) {
            instance
              ..onDown = onHorizontalDragDown
              ..onUpdate = onHorizontalDragUpdate
              ..onEnd = onHorizontalDragEnd;
          },
        );
    animationController = AnimationController(
        lowerBound: -maxDragDistance,
        upperBound: 0,
        vsync: this,
        duration: const Duration(milliseconds: 300))
      ..addListener(() {
        translateX = animationController.value;
        mountedState();
      });
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(child: Stack(
      children: <Widget>[
        Positioned.fill(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: widget.buttons.asMap().keys.map((item) {
                return GestureDetector(
                  onTap:(){
                    if(widget.autoClose!) close();
                    widget.onClick( this, item);
                  },
                  child: SizedBox(
                    width: widget.singleButtonWidth,
                    height: double.infinity,
                    child: widget.buttons[item],
                  ),
                );
              }).toList(),
            )),
        GestureDetector(
          onHorizontalDragUpdate: onHorizontalDragUpdate,
          onHorizontalDragDown: onHorizontalDragDown,
          onHorizontalDragEnd: onHorizontalDragEnd,
          child: Transform.translate(
            offset: Offset(translateX, 0),
            child: widget.child,
          ),
        )
      ],
    ), onWillPop: ()async{
      if (translateX != 0){
        close();
        return false;
      }
      return true;
    });
  }

  //按下事件 并且可能要开始横向滑动
  void onHorizontalDragDown(DragDownDetails details) {
    if (widget.onSlideStarted != null){
      widget.onSlideStarted!.call();
    }
  }

  //横向滑动回调
  void onHorizontalDragUpdate(DragUpdateDetails details) {
    translateX = (translateX + details.delta.dx).clamp(-maxDragDistance, 0.0);
    mountedState();
  }

  //横向滑动结束
  void onHorizontalDragEnd(DragEndDetails details) {
    animationController.value = translateX;
    if (details.velocity.pixelsPerSecond.dx > 200) {
      close();
    } else if (details.velocity.pixelsPerSecond.dx < -200) {
      open();
    } else {
      if (translateX.abs() > maxDragDistance / 2) {
        open();
      } else {
        close();
      }
    }
  }

  void open() {
    if (translateX != -maxDragDistance) {
      animationController.animateTo(-maxDragDistance).then((_) {
        if (widget.onSlideCompleted != null) widget.onSlideCompleted!.call();
      });
    }
  }

  void close() {
    if (translateX != 0) {
      animationController.animateBack(0).then((_) {
        if (widget.onSlideCanceled != null) widget.onSlideCanceled!.call();
      });
    }
  }

  @override
  void dispose() {
    animationController.dispose();
    super.dispose();
  }

}
